float4x4 World;
float4x4 View;
float4x4 Projection;

//color of the light 
float3 Color; 

//position of the camera, for specular light
float3 cameraPosition; 

//this is used to compute the world-position
float4x4 InvertViewProjection; 

//this is the position of the light
float3 lightPosition;

//how far does this light reach
FLOAT lightRadius;

//control the brightness of the light
FLOAT lightIntensity = 1.0f;

// diffuse color, and specularIntensity in the alpha channel
texture colorMap;
sampler colorSampler = sampler_state
{
	Texture = <colorMap>;
	MagFilter = LINEAR;
	MinFilter = LINEAR;
	Mipfilter = LINEAR;
	
	AddressU = CLAMP;
	AddressV = CLAMP;
};

// normals, and specularPower in the alpha channel
texture normalMap;
sampler normalSampler = sampler_state
{
	Texture = <normalMap>;
	AddressU = CLAMP;
	AddressV = CLAMP;
};

//depth
texture depthMap;
sampler depthSampler = sampler_state
{
	Texture = <depthMap>;
	AddressU = CLAMP;
	AddressV = CLAMP;
};

struct VertexShaderInput
{
	float3 Position : POSITION0;
};

struct VertexShaderOutput
{
	float4 Position : POSITION0;
	float4 ScreenPosition : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
	VertexShaderOutput output;
	
	//processing geometry coordinates
	float4 worldPosition = mul(float4(input.Position,1), World);
	float4 viewPosition = mul(worldPosition, View);
	output.Position = mul(viewPosition, Projection);
	output.ScreenPosition = output.Position;
	
	return output;
}

float2 halfPixel;
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	//obtain screen position
	input.ScreenPosition.xy /= input.ScreenPosition.w;

	//obtain textureCoordinates corresponding to the current pixel
	//the screen coordinates are in [-1,1]*[1,-1]
	//the texture coordinates need to be in [0,1]*[0,1]
	float2 texCoord = 0.5f * (float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 1);
	
	//allign texels to pixels
	texCoord -=halfPixel;

	//get normal data from the normalMap
	float4 normalData = tex2D(normalSampler,texCoord);
	
	//tranform normal back into [-1,1] range
	float3 normal = 2.0f * normalData.xyz - 1.0f;
	
	//get specular power
	FLOAT specularPower = normalData.a * 255;
	
	//get specular intensity from the colorMap
	FLOAT specularIntensity = tex2D(colorSampler, texCoord).a;

	//read depth
	FLOAT depthVal = tex2D(depthSampler,texCoord).r;

	//compute screen-space position
	float4 position;
	position.xy = input.ScreenPosition.xy;
	position.z = depthVal;
	position.w = 1.0f;
	
	//transform to world space
	position = mul(position, InvertViewProjection);
	position /= position.w;

	//surface-to-light vector
	float3 lightVector = lightPosition - position;

	//compute attenuation based on distance - linear attenuation
	FLOAT attenuation = saturate(1.0f - length(lightVector)/lightRadius);

	//normalize light vector
	lightVector = normalize(lightVector); 

	//compute diffuse light
	FLOAT NdL = max(0,dot(normal,lightVector));
	float3 diffuseLight = NdL * Color.rgb;

	//reflection vector
	float3 reflectionVector = normalize(reflect(-lightVector, normal));
	
	//camera-to-surface vector
	float3 directionToCamera = normalize(cameraPosition - position);
	
	//compute specular light
	FLOAT specularLight = specularIntensity * pow(saturate(dot(reflectionVector, directionToCamera)), specularPower);

	//take into account attenuation and lightIntensity.
	return attenuation * lightIntensity * float4(diffuseLight.rgb,specularLight);
}

technique Technique1
{
	pass Pass1
	{
		ZEnable = false;
		ZWriteEnable = false;
	
		VertexShader = compile vs_2_0 VertexShaderFunction();
		PixelShader = compile ps_2_0 PixelShaderFunction();
	}
}